home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n05 / ipx.asc < prev    next >
Encoding:
Text File  |  1992-03-30  |  19.5 KB  |  443 lines

  1. _IPX: THE GREAT COMMUNICATOR_
  2. by Rahner James
  3.  
  4. [LISTING ONE]
  5.  
  6. ; ***************************************************************************
  7. ; * Title: ESRS.ASM -- by Rahner James
  8. ; * Copyright (c) January 1991, Ryu Consulting, 916/722-1939
  9. ; * File contains default Event Service Routine for listening & talking packets
  10. ; ****************************************************************************
  11.  
  12. _ESRS_ASM_  equ 1
  13. ifdef   LARGEMODEL
  14.     .model  large,c
  15. else
  16.     .model  small,c
  17. endif
  18. ADDRESS_S struct
  19.     network     dw  ?,? ; Network number
  20.     node        dw  3 dup(?); Node address on that network
  21.     socket      dw  ?   ; Socket number on that node
  22. ADDRESS_S ends
  23. IPX_PACKET_S struct
  24.     next        dd  ?  ; Used by IPX/SPX when the ECB is active
  25.     function    dd  ?  ; Called after packet sent/recd, called ESR
  26.     in_use      db  ?  ; Set to !0 by IPX/SPX when packet is in use
  27.     completion_code db  ?  ; Set by XPX after packet task is complete
  28.     socket      dw  ?  ; Socket to use for this ECB
  29.     IPX_work    dd  ?  ; Workspace used internally by IPX
  30.     driver_work dd  ?,?,? ; Workspace used internally by IPX driver
  31.     dest_address    db  6 dup(?); Destination address for packet
  32.     fragment_count  dw  ?   ; Fragments descriptors that follow
  33.     hdr     dd  ?   ; -> IPX/SPX packet descriptor to use
  34.     size_hdr    dw  ?   ; Size of the IPX(30) or SPX(42) descriptor
  35.     buffer_ptr  dd  ?   ; -> data buffer to use for transmission/reception
  36.     buffer_size dw  ?   ; Number of bytes in that buffer
  37.     next_allocated  dd  ?   ; -> next allocated packet structure
  38.     next_sibling    dd  ?   ; -> next packet for stream and condition
  39.     parent      dd  ?   ; -> parent stream definition packet
  40.     default_buffer  dd  ?   ; -> default buffer to use for IPX or SPX
  41.     default_size    dw  ?   ; Size of the default buffer
  42.     done_flag   dd  ?   ; Set by the ESR with the completion code
  43.  
  44.     checksum    dw  ?   ; Dummy checksum of 30-byte packet header
  45.     packet_length   dw  ?   ; Length of complete IPX packet 
  46.     control     db  ? ; Transport control byte for internet bridges
  47.     packet_type db  ?   ; Packet type: IPX(4)/SPX(5) 
  48.  
  49.     dest_network    dd  ?   ; Destination network address
  50.     dest_node   db  6 dup(?); Destination node address
  51.     dest_socket dw  ?   ; Destination socket
  52.  
  53.     src_network dd  ?   ; Source network address
  54.     src_node    db  6 dup(?); Source node address
  55.     src_socket  dw  ?   ; Source socket
  56. IPX_PACKET_S ends
  57. XPX_STREAM_S struct
  58.     next        dd  ?   ; -> next stream structure opened
  59.     first_allocated dd  ?   ; -> first allocated packet for handle
  60.     last_allocated  dd  ?   ; -> last allocated packet for handle
  61.     first_unread    dd  ?   ; -> first unread packet
  62.     last_unread dd  ?   ; -> last unread packet in the list
  63.     first_free  dd  ?   ; -> first packet available for talking
  64.     first_error dd  ?   ; -> first packet encountering an error
  65.     last_error  dd  ?   ; -> last packet encountering an error
  66.  
  67.     dest_network    dd  ?   ; Destination network address
  68.     dest_node   db  6 dup(?); Destination node address
  69.     dest_socket dw  ?   ; Destination socket
  70.     local_target    db  6 dup(?); Node address of local target for dest
  71.     connection_ID   dw  ?   ; Connection ID used for SPX
  72.     total_talkers   dw  ?   ; Number of talkers for this stream
  73.     total_listeners dw  ?   ; Number of listeners for this stream
  74.     unread_count    dw  ?   ; Number of packets unread by app
  75.     free_count  dw  ?   ; Number of packets ready for talking
  76.     maximum_unread  dw  ?   ; Maximum number of unread packets 
  77.     error_count dw  ?   ; Number of unprocessed error packets
  78.  
  79.     total_transmissions dd  ?   ; Number of transmissions performed 
  80.     total_receptions    dd  ?   ; Number of receptions performed 
  81.     total_errors    dd  ?   ; Number of errors encountered 
  82. XPX_STREAM_S ends
  83.  .data
  84.         extern  _Ignore_Nomatch:byte, _Our_Address:word, IPX_Vector:dword, 
  85.                                                             _First_Stream:dword
  86.     extern  _First_Nomatch:dword, _Last_Nomatch:dword, _Total_Nomatchs:word
  87.  .code
  88. Last_Broad_Ptr      dw  0,0 ; -> last checked broadcast stream 
  89.  
  90. ; ****************************************************************************
  91. ; *  void far TALK_ESR( void ) -- Event Service Routine (ESR) for IPX 
  92. ; *  functions and their talking packets 
  93. ; *  Given: AL = 0 if AES called this ESR, 0xff if this is a normal event 
  94. ; *     ES:SI -> ECB that just finished talking
  95. ; *  Returns: Packet either glued onto the free list or the error list
  96. ; *  Note: Interrupts are enabled at this point and should stay that way
  97. ; ****************************************************************************
  98. talk_esr proc far
  99. ; * See if we need to set the done flag
  100.     lds bx, es:[si].IPX_PACKET_S.done_flag ; DS:BX -> process done flag
  101.     mov cl, es:[si].IPX_PACKET_S.completion_code
  102.     mov ax, ds
  103.     or  ax, bx
  104.     jz  @F          ; If DS:BX -> NULL, just skip it
  105.     mov [bx], cl        ; Set the flag with our completion code
  106.     mov word ptr es:[si].IPX_PACKET_S.done_flag, 0 ; Make it NULL 
  107.     mov word ptr es:[si].IPX_PACKET_S.done_flag+2, 0
  108. ; * Check whether the packet goes in the error list or the free list
  109. @@: lds bx, es:[si].IPX_PACKET_S.parent    ; DS:BX -> parent structure
  110.     or  cl, cl            ; See if we got a transmission error
  111.     jnz talk20_esr        ; Jump if we got one
  112. ; * Here's where we process the good transmissions
  113.     add word ptr [bx].XPX_STREAM_S.total_transmissions, 1
  114.     adc word ptr [bx].XPX_STREAM_S.total_transmissions+2, 0
  115.     inc [bx].XPX_STREAM_S.free_count;
  116.     mov cx, word ptr [bx].XPX_STREAM_S.first_free ; DX:CX -> first free
  117.     mov dx, word ptr [bx].XPX_STREAM_S.first_free+2
  118.     mov word ptr [bx].XPX_STREAM_S.first_free, si  
  119.     mov word ptr [bx].XPX_STREAM_S.first_free+2, es
  120.     mov word ptr es:[si].IPX_PACKET_S.next_sibling, cx  
  121.     mov word ptr es:[si].IPX_PACKET_S.next_sibling+2, dx
  122. talk10_esr:
  123.     ret
  124. ; * Here's where we take care of our challenged packets
  125. talk20_esr:
  126.     add word ptr [bx].XPX_STREAM_S.total_errors, 1
  127.     adc word ptr [bx].XPX_STREAM_S.total_errors+2, 0
  128.     inc [bx].XPX_STREAM_S.error_count
  129.     mov cx, word ptr [bx].XPX_STREAM_S.last_error ; DX:CX ->last error 
  130.     mov dx, word ptr [bx].XPX_STREAM_S.last_error+2
  131.     mov word ptr [bx].XPX_STREAM_S.last_error, si ; Set new last error
  132.     mov word ptr [bx].XPX_STREAM_S.last_error+2, es
  133.     mov word ptr es:[si].IPX_PACKET_S.next_sibling, 0
  134.     mov word ptr es:[si].IPX_PACKET_S.next_sibling+2, 0
  135.     mov ax, cx             ; See if we need to do the first as well
  136.     or  ax, dx
  137.     jnz @F
  138.     mov word ptr [bx].XPX_STREAM_S.first_error, si ;Set new first error
  139.     mov word ptr [bx].XPX_STREAM_S.first_error+2, es
  140.     ret
  141. @@: mov ds, dx                        ; DS:BX -> the first born
  142.     mov bx, cx
  143.     mov word ptr [bx].IPX_PACKET_S.next_sibling, si ; Point old end 
  144.     mov word ptr [bx].IPX_PACKET_S.next_sibling+2, es
  145.     ret
  146. talk_esr endp
  147.  
  148. ; ****************************************************************************
  149. ; *  void far LISTEN_ESR( void ) -- Event Service Routine (ESR) for IPX 
  150. ; *  functions and their listening packets
  151. ; *  Given:  AL = 0 if AES called this ESR, 0xff if this is a normal event 
  152. ; *          ES:SI -> ECB that just got something
  153. ; *  Returns: Packet put at the end of the unread packet list of the stream it 
  154. ; *  was intended for.
  155. ; *  Note: Interrupts are enabled at this point and should stay that way. This 
  156. ; *  packet may not be put with its parent if there are multiple parents
  157. ; *  associated with one socket
  158. ; ****************************************************************************
  159. listen_esr proc far
  160.     mov ax, @Data               ; DS = our data segment
  161.     mov ds, ax
  162. ; * First see if we sent it as a broadcast and it got back to us
  163.     mov ax, _Our_Address.ADDRESS_S.node+4               
  164.     cmp word ptr es:[si].IPX_PACKET_S.src_node+4, ax    
  165.     jne listen10_esr                    
  166.     mov ax, _Our_Address.ADDRESS_S.node+2       
  167.     cmp word ptr es:[si].IPX_PACKET_S.src_node+2, ax    
  168.     jne listen10_esr
  169.     mov ax, _Our_Address.ADDRESS_S.node
  170.     cmp word ptr es:[si].IPX_PACKET_S.src_node, ax
  171.     jne listen10_esr
  172.     mov ax, _Our_Address.ADDRESS_S.network+2
  173.     cmp word ptr es:[si].IPX_PACKET_S.src_network+2, ax
  174.     jne listen10_esr
  175.     mov ax, _Our_Address.ADDRESS_S.network
  176.     cmp word ptr es:[si].IPX_PACKET_S.src_network, ax
  177.     jne listen10_esr
  178. listen_again_buckwheat:
  179.     mov bx, 4           ; BX = IPX Listen For Packet command
  180.     call    dword ptr IPX_Vector    ; Call the IPX function
  181.     ret
  182. ; * See if we need to set the done flag
  183. listen10_esr:
  184.     mov ax, es:[si].IPX_PACKET_S.packet_length  ; Change format
  185.     xchg    ah, al
  186.     sub ax, es:[si].IPX_PACKET_S.size_hdr
  187.     mov es:[si].IPX_PACKET_S.packet_length, ax
  188.  
  189.     lds bx, es:[si].IPX_PACKET_S.done_flag ; DS:BX -> process done flag
  190.     mov cl, es:[si].IPX_PACKET_S.completion_code
  191.     mov ax, ds
  192.     or  ax, bx
  193.     jz  listen20_esr                            
  194.     mov [bx], cl                    
  195.     mov word ptr es:[si].IPX_PACKET_S.done_flag, 0  
  196.     mov word ptr es:[si].IPX_PACKET_S.done_flag+2, 0
  197. ; * Check whether the packet goes in the error list or the free list
  198. listen20_esr:
  199.     lds bx, es:[si].IPX_PACKET_S.parent   ; DS:BX -> parent structure
  200.     or  cl, cl                ; See if we got a reception error
  201.     jz  listen40_esr         ; Jump if we have an unimpaired reception
  202. ; * Here's where we take care of our datistically challenged packets
  203.     add word ptr [bx].XPX_STREAM_S.total_errors, 1
  204.     adc word ptr [bx].XPX_STREAM_S.total_errors+2, 0
  205.     inc [bx].XPX_STREAM_S.error_count
  206.     mov cx, word ptr [bx].XPX_STREAM_S.last_error ; DX:CX->last error 
  207.     mov dx, word ptr [bx].XPX_STREAM_S.last_error+2
  208.     mov word ptr [bx].XPX_STREAM_S.last_error, si ; Set new last error
  209.     mov word ptr [bx].XPX_STREAM_S.last_error+2, es
  210.     mov word ptr es:[si].IPX_PACKET_S.next_sibling, 0   
  211.     mov word ptr es:[si].IPX_PACKET_S.next_sibling+2, 0
  212.     mov ax, dx            ; See if we are the only packet here
  213.     or  ax, cx
  214.     jnz @F           ; Skip out of this ESR if we are not alone
  215.     mov word ptr [bx].XPX_STREAM_S.first_error, si ;Set new first error
  216.     mov word ptr [bx].XPX_STREAM_S.first_error+2, es
  217.     ret
  218. @@: mov ds, dx                   ; DS:BX -> the first born
  219.     mov bx, cx
  220.     mov word ptr [bx].IPX_PACKET_S.next_sibling, si 
  221.     mov word ptr [bx].IPX_PACKET_S.next_sibling+2, es
  222.     ret
  223. ; * Here's where we process the good transmissions
  224. listen40_esr:
  225.     push    ds            ; DX:CX -> the first stream structure
  226.     mov ax, @Data
  227.     mov ds, ax
  228.     mov cx, word ptr _First_Stream
  229.     mov dx, word ptr _First_Stream+2
  230.     pop ds
  231.     mov Last_Broad_Ptr, 0
  232.     mov Last_Broad_Ptr+2, 0
  233. listen50_esr:
  234.     cmp [bx].XPX_STREAM_S.total_listeners, 0 ; See if READ ONLY stream
  235.     jz  not_parent           ; Skip this one if it is READ ONLY
  236.     mov ax, word ptr [bx].XPX_STREAM_S.dest_node 
  237.     and ax, word ptr [bx].XPX_STREAM_S.dest_node+2
  238.     and ax, word ptr [bx].XPX_STREAM_S.dest_node+4
  239.     inc ax
  240.     jnz @F            ; Skip if it is not a broadcast type
  241.     mov Last_Broad_Ptr, bx    ; Save this for later
  242.     mov Last_Broad_Ptr+2, ds
  243.     jmp short not_parent      ; Still not necessarily the right one
  244. @@: mov ax, word ptr [bx].XPX_STREAM_S.local_target+4   ; Match parent 
  245.     cmp word ptr es:[si].IPX_PACKET_S.src_node+4, ax
  246.     jne not_parent          
  247.     mov ax, word ptr [bx].XPX_STREAM_S.local_target+2
  248.     cmp word ptr es:[si].IPX_PACKET_S.src_node+2, ax
  249.     jne not_parent
  250.     mov ax, word ptr [bx].XPX_STREAM_S.local_target
  251.     cmp word ptr es:[si].IPX_PACKET_S.src_node, ax
  252.     jne not_parent
  253.     mov ax, word ptr es:[si].IPX_PACKET_S.src_network+2
  254.     cmp word ptr es:[si].IPX_PACKET_S.dest_network+2, ax
  255.     jne not_parent
  256.     mov ax, word ptr es:[si].IPX_PACKET_S.src_network
  257.     cmp word ptr es:[si].IPX_PACKET_S.dest_network, ax
  258.     je  found_listener
  259. ; * At this point, the current structure has been determined not to be suitable
  260. not_parent:
  261.     mov ax, cx              ; See if we are at the end of our rope
  262.     or  ax, dx
  263.     jz  no_listener         ; No stream match found
  264.  
  265.     mov ds, dx              ; DS:BX -> next stream definition
  266.     mov bx, cx
  267.     mov cx, word ptr [bx].XPX_STREAM_S.next ; DX:CX -> next stream 
  268.     mov dx, word ptr [bx].XPX_STREAM_S.next+2
  269.     jmp listen50_esr                ; Loop until we poop
  270. ; * Stream ID matches up with destination address, so add packet to stream list
  271. found_listener:
  272.     add word ptr [bx].XPX_STREAM_S.total_receptions, 1
  273.     adc word ptr [bx].XPX_STREAM_S.total_receptions+2, 0
  274.     inc [bx].XPX_STREAM_S.unread_count
  275.     mov ax, [bx].XPX_STREAM_S.unread_count  ; Update our statistics
  276.     cmp [bx].XPX_STREAM_S.maximum_unread, ax
  277.     jnc found10_listener            ; Skip if no need to update
  278.     mov [bx].XPX_STREAM_S.maximum_unread, ax
  279. found10_listener:
  280.     mov cx, word ptr [bx].XPX_STREAM_S.last_unread 
  281.     mov dx, word ptr [bx].XPX_STREAM_S.last_unread+2
  282.     mov word ptr [bx].XPX_STREAM_S.last_unread, si  
  283.     mov word ptr [bx].XPX_STREAM_S.last_unread+2, es
  284.     mov word ptr es:[si].IPX_PACKET_S.next_sibling, 0   
  285.     mov word ptr es:[si].IPX_PACKET_S.next_sibling+2, 0
  286.     mov ax, cx             ; See if we need to do the first as well
  287.     or  ax, dx
  288.     jnz @F             ; All done if there are others
  289.     mov word ptr [bx].XPX_STREAM_S.first_unread, si 
  290.     mov word ptr [bx].XPX_STREAM_S.first_unread+2, es
  291.     ret
  292. @@: mov ds, dx                   ; DS:BX -> the first born
  293.     mov bx, cx
  294.     mov word ptr [bx].IPX_PACKET_S.next_sibling, si
  295.     mov word ptr [bx].IPX_PACKET_S.next_sibling+2, es
  296.     ret
  297. ; * At this point, packet is an orphan and must be sent off to farm or be glue
  298. no_listener:
  299.     lds bx, dword ptr Last_Broad_Ptr ; DS:BX->last broadcast stream
  300.     mov ax, ds
  301.     or  ax, bx
  302.     jnz found_listener  ; If one was found, use as last resort
  303.     cmp _Ignore_Nomatch, al ; Ignore orphans or adopt 
  304.     jmp listen_again_buckwheat  ; Put back on the mountaintop
  305. no10_listener:
  306.     mov ax, @Data       ; DS = our most lovable data segment
  307.     mov ds, ax
  308.     inc _Total_Nomatchs
  309.     mov cx, word ptr _Last_Nomatch     ; DX:CX -> last error packet
  310.     mov dx, word ptr _Last_Nomatch+2
  311.     mov word ptr _Last_Nomatch, si         ; Make it point to us
  312.     mov word ptr _Last_Nomatch+2, es
  313.     mov word ptr es:[si].IPX_PACKET_S.next_sibling, 0
  314.     mov word ptr es:[si].IPX_PACKET_S.next_sibling+2, 0
  315.     mov ax, cx             ; See if we need to do the first as well
  316.     or  ax, dx
  317.     jnz @F          ; All done if there are others
  318.     mov word ptr _First_Nomatch, si    ; Set us as the new first error
  319.     mov word ptr _First_Nomatch+2, es
  320.     ret
  321. @@: mov ds, dx          ; DS:BX -> the first born
  322.     mov bx, cx
  323.     mov word ptr [bx].IPX_PACKET_S.next_sibling, si
  324.     mov word ptr [bx].IPX_PACKET_S.next_sibling+2, es
  325.     ret
  326. listen_esr endp
  327.     end
  328.  
  329.  
  330.  
  331. [LISTING TWO]
  332.  
  333. ; ****************************************************************************
  334. ; * Title:  XPX_INIT.ASM -- Rahner James
  335. ; * Copyright (c) December 1991, Ryu Consulting, 916/722-1939
  336. ; * File contains all the functions to support initializing IPX engine
  337. ; ****************************************************************************
  338.  
  339. _XPX_INIT_ASM_  equ 1
  340.     include network.inc
  341.  .data
  342.         public IPX_Vector, _Socket_Life, _SPX_Version, _SPX_Max_Connections, 
  343.                                                                   _Our_Address
  344.     public  _SPX_Available_Connections, _SPX_Retry_Count
  345.  
  346. IPX_Vector    dw    offset dummy_IPX_function,@Code   ; -> IPX support function
  347. _Socket_Life           db  0    ; 0=socket closed at app termination 
  348.                     ; 0ffh= socket closed when requested
  349. _SPX_Version           dw  0    ; SPX version #: MSByte=major, LSByte=minor
  350. _SPX_Max_Connections       dw  0    ; Max number of SPX connections
  351. _SPX_Available_Connections dw  0    ; # of SPX connections available to app
  352. _SPX_Retry_Count       db  0    ; Retry count for SPX establish connection
  353. _SPX_Bowser_Flag       db  1    ; Watchdog flag, 0=disable, 1=enable
  354. _Our_Address label dword            ; Global access for this structure
  355. network            dd  0    ; Network address
  356. node               db  6 dup(0) ; Node address
  357. socket             dw  0    ; Socket number
  358.  
  359.  .code
  360. ; ****************************************************************************
  361. ; * int XPX_INIT( us SOCKET_NUMBER ) -- Initializes all IPX/SPX internals
  362. ; * Given: SOCKET_NUMBER = socket number to open for listening, 0 opens 
  363. ; *             the next available
  364. ; * Returns: 0 if IPX was initialized successfully
  365. ; *     -1 = socket already open (!)
  366. ; *     -2 = socket table full
  367. ; *     -3 = IPX or SPX is not installed
  368. ; *  Note: Initializes IPX vector, opens a listening socket for IPX driver. 
  369. ; *  Internal vectors, counter, & pointers are brought to initial conditions
  370. ; ****************************************************************************
  371. xpx_init proc uses di si, socket_number:word
  372.     mov ax, 7a00h       ; Get the IPX vector
  373.     int 2fh         ; Query the DOS multiplexer
  374.     inc al          ; AL = 0ffh if IPX is there
  375.     jnz derr_xpx_init       ; Quit in disgrace if it's not there
  376.     mov IPX_Vector, di          ; IPX function vector returned in ES:DI
  377.     mov IPX_Vector+2, es
  378. ; * See if we need to close the old stuff down
  379.     mov dx, socket
  380.     or  dx, dx          ; See if we opened a socket
  381.     jz  xpx10_init      ; Skip if we didn't
  382.     cmp socket_number, 0    
  383.     jz  xpx20_init      ; Skip if so
  384.     cmp socket_number, dx   ; See if it's the same as before
  385.     je  xpx20_init      ; Skip if it is
  386.     IPX 1           ; IPX Close Socket command
  387. ; * Now, open the socket 
  388. xpx10_init:
  389.     mov dx, socket_number
  390.     mov al, _Socket_Life
  391.     IPX_CHECK   0       ; IPX Open Socket command
  392.     jnz done_xpx_init       ; Quit if an error
  393. xpx20_init:
  394.     mov socket, dx
  395. ; * Get our internetwork address
  396.     mov ax, ds          ; ES = DS
  397.     mov es, ax
  398.     mov si, offset network
  399.     mov di, si
  400.     IPX 9           ; IPX Get Internetwork Address command
  401. ; * Last, we have to initialize the SPX interface
  402.     xor ax, ax
  403.     IPX_CHECK   10h     ; SPX Initialize command
  404.     jz  derr_xpx_init       ; Quit if it's not there
  405.     mov _SPX_Version, bx    ; Save the information returned
  406.     mov _SPX_Max_Connections, cx
  407.     mov _SPX_Available_Connections, dx
  408.     xor ax, ax          ; Good return
  409.     jmp short done_xpx_init
  410. derr_xpx_init:
  411.     mov al, -3          ; It's gone McCreedy!
  412. done_xpx_init:
  413.     cbw
  414.     ret
  415. xpx_init endp
  416.  
  417. ; ****************************************************************************
  418. ; * int DUMMY_IPX_FUNCTION( void ) -- Dummy function that returns error 
  419. ; *      code -10 so that system will not hang if not initialized
  420. ; * Given: nothing
  421. ; * Returns: -10 always
  422. ; ****************************************************************************
  423. dummy_IPX_function proc far
  424.     mov ax, -10
  425.     ret
  426. dummy_IPX_function endp
  427.     end
  428.  
  429.  
  430.  
  431. Example 1:
  432.  
  433.      mov  ax, 7a00h           ; Function 7Ah, AL = 0
  434.      int  2fh                 ; MS-DOS Multiplex interrupt
  435.                               ; Returns with AL == 0FFh if xPX
  436.                               ;  exists and ES:DI == xPX vector
  437.  
  438.      inc  al                  ; Set ZERO if AL == -1
  439.      jnz  outta_here          ; Quit if xPX isn't around
  440.      mov  IPX_Vector, di      ; Save the xPX entry vector
  441.      mov  IPX_Vector+2, es
  442.  
  443.